package org.mv.mm.docs;

import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.mv.mm.api.Doc;
import org.mv.mm.api.capabilities.IRefreshableDocViewCapability;
import org.mv.mm.api.capabilities.IReloadableDocCapability;
import org.mv.mm.api.capabilities.ISaveableDocCapability;
import org.mv.mm.api.data.IDataProvider;
import org.mv.mm.common.CentralLookup;
import org.mv.mm.common.ILinkedWindow;
import org.mv.mm.docs.nodes.DocNode;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.cookies.SaveCookie;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(dtd = "-//org.mv.mm.docs//DocEdit//EN",
autostore = false)
@TopComponent.Description(preferredID = "DocEditTopComponent",
//iconBase="SET/PATH/TO/ICON/HERE", 
persistenceType = TopComponent.PERSISTENCE_NEVER)
@TopComponent.Registration(mode = "editor", openAtStartup = false)
@ActionID(category = "Window", id = "org.mv.mm.docs.DocEditTopComponent")
@ActionReference(path = "Menu/Window" /*
 * , position = 333
 */)
@TopComponent.OpenActionRegistration(displayName = "#CTL_DocEditAction",
preferredID = "DocEditTopComponent")
@Messages({
  "CTL_DocEditAction=DocEdit",
  "CTL_DocEditTopComponent=Document edit dialog",
  "HINT_DocEditTopComponent=This is a dialog for editing the documents."
})
public final class DocEditTopComponent extends TopComponent implements LookupListener {

  private TopComponent tcOpenedFrom;
  private Lookup.Result<DocNode> docNodeResult = null;
  private Lookup.Result<Doc> docResult = null;
  private Lookup.Result<IDataProvider> providerResult = null;
  private DocNode docNode = null;
  private Lookup.Result<Node> cNodeResult = null;
  private Doc doc = null;
  private IDataProvider dataProvider = null;
  private final InstanceContent content;
  private final SaveableViewCapability impl;
  private final ShowParentCookie showPar;
  private static final Logger logger = Logger.getLogger(DocEditTopComponent.class.getName());

  public DocEditTopComponent() {
    initComponents();
    setName(Bundle.CTL_DocEditTopComponent());
    setToolTipText(Bundle.HINT_DocEditTopComponent());

    docWorkName.getDocument().addDocumentListener(new DocumentListener() {

      @Override
      public void insertUpdate(DocumentEvent e) {
        fire(true);
      }

      @Override
      public void removeUpdate(DocumentEvent e) {
        fire(true);
      }

      @Override
      public void changedUpdate(DocumentEvent e) {
        fire(true);
      }
    });

    //Create a new instance of our SaveCookie implementation:
    impl = new SaveableViewCapability();

    showPar = new ShowParentCookie();

    //Create a new instance of our dynamic object:
    content = new InstanceContent();

    /*
     * Add the ShowParentCookie to context, so the action to show the parent
     * window is active.
     */
    content.add(showPar);

    //Add the dynamic object to the TopComponent Lookup:
    associateLookup(new AbstractLookup(content));
  }

  /**
   * This method is called from within the constructor to initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is always
   * regenerated by the Form Editor.
   */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        docWorkName = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();
        docTitle = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        docDescrip = new javax.swing.JTextArea();
        docAuthor = new javax.swing.JTextField();
        jLabel5 = new javax.swing.JLabel();
        docAbbrev = new javax.swing.JTextField();

        docWorkName.setText(org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.docWorkName.text")); // NOI18N
        docWorkName.setToolTipText(org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.docWorkName.toolTipText")); // NOI18N
        docWorkName.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                docWorkNameFocusLost(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.jLabel1.text")); // NOI18N
        jLabel1.setToolTipText(org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.jLabel1.toolTipText")); // NOI18N

        docTitle.setText(org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.docTitle.text")); // NOI18N
        docTitle.setToolTipText(org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.docTitle.toolTipText")); // NOI18N

        jLabel2.setLabelFor(docTitle);
        org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.jLabel2.text")); // NOI18N
        jLabel2.setToolTipText(org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.jLabel2.toolTipText")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.jLabel3.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.jLabel4.text")); // NOI18N

        docDescrip.setColumns(20);
        docDescrip.setRows(5);
        jScrollPane1.setViewportView(docDescrip);

        docAuthor.setText(org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.docAuthor.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(jLabel5, org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.jLabel5.text")); // NOI18N

        docAbbrev.setText(org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.docAbbrev.text")); // NOI18N
        docAbbrev.setToolTipText(org.openide.util.NbBundle.getMessage(DocEditTopComponent.class, "DocEditTopComponent.docAbbrev.toolTipText")); // NOI18N

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel2)
                    .addComponent(jLabel1)
                    .addComponent(jLabel3)
                    .addComponent(jLabel4))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(docAuthor)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 287, Short.MAX_VALUE)
                    .addComponent(docTitle)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(docWorkName, javax.swing.GroupLayout.PREFERRED_SIZE, 145, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jLabel5)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(docAbbrev)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel2)
                    .addComponent(docTitle, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(docWorkName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel5)
                    .addComponent(docAbbrev, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel3)
                    .addComponent(docAuthor, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel4)
                        .addGap(0, 0, Short.MAX_VALUE))
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 200, Short.MAX_VALUE))
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

  private void docWorkNameFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_docWorkNameFocusLost
    if (docAbbrev.getText().isEmpty()) {
      docAbbrev.setText(docWorkName.getText().substring(0, 2).toUpperCase());
    }
  }//GEN-LAST:event_docWorkNameFocusLost

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextField docAbbrev;
    private javax.swing.JTextField docAuthor;
    private javax.swing.JTextArea docDescrip;
    private javax.swing.JTextField docTitle;
    private javax.swing.JTextField docWorkName;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JScrollPane jScrollPane1;
    // End of variables declaration//GEN-END:variables

  @Override
  public void componentOpened() {
    this.tcOpenedFrom = WindowManager.getDefault().getRegistry().getActivated();

    docNodeResult = tcOpenedFrom.getLookup().lookupResult(DocNode.class);

    cNodeResult = tcOpenedFrom.getLookup().lookupResult(Node.class);
    cNodeResult.addLookupListener(this);

    docResult = tcOpenedFrom.getLookup().lookupResult(Doc.class);
    providerResult = tcOpenedFrom.getLookup().lookupResult(IDataProvider.class);

    docNodeResult.addLookupListener(this);
    docResult.addLookupListener(this);
    providerResult.addLookupListener(this);
    
    // Display detail right after opening
    resultChanged(null);
  }

  @Override
  public void componentClosed() {
    cNodeResult.removeLookupListener(this);

    docNodeResult.removeLookupListener(this);
    providerResult.removeLookupListener(this);
    docResult.removeLookupListener(this);
  }

  void writeProperties(java.util.Properties p) {
    // better to version settings since initial version as advocated at
    // http://wiki.apidesign.org/wiki/PropertyFiles
    p.setProperty("version", "1.0");
    // TODO store your settings
  }

  void readProperties(java.util.Properties p) {
    String version = p.getProperty("version");
    // TODO read your settings according to their version
  }

  @Override
  public void resultChanged(LookupEvent le) {
    //Get the data provider:
    Collection<? extends IDataProvider> allQueries = providerResult.allInstances();
    Iterator<? extends IDataProvider> it1 = allQueries.iterator();
    while (it1.hasNext()) {
      dataProvider = (IDataProvider) it1.next();
    }
    //Get the document:
    Collection<? extends Doc> allDocs = docResult.allInstances();
    Iterator<? extends Doc> it2 = allDocs.iterator();
    while (it2.hasNext()) {
      doc = (Doc) it2.next();

      setDisplayName(doc.getWorkName());

      docAbbrev.setText(doc.getAbbrev());
      docWorkName.setText(doc.getWorkName());
      docTitle.setText(doc.getTitle());
      docAuthor.setText(doc.getAuthor());
      docDescrip.setText(doc.getDescription());

    }
    //Get the node:
    Collection<? extends DocNode> allNodes = docNodeResult.allInstances();

    //Close this T.C., when the original one, from which this one is opened, has been closed.
    //if (allNodes.isEmpty()) {
    if (!this.tcOpenedFrom.isOpened()) {
      this.close();
    } else {
      Iterator<? extends DocNode> it3 = allNodes.iterator();
      while (it3.hasNext()) {
        docNode = it3.next();

        //TODO je to potřeba?
        setActivatedNodes(new DocNode[]{docNode});
        content.add(docNode);

      }
    }
  }

  public void fire(boolean modified) {
    if (modified) {
      //If the text is modified,
      //we add SaveCookie impl to Lookup:
      content.add(impl);
    } else {
      //Otherwise, we remove the SaveCookie impl from the lookup:
      content.remove(impl);
    }
  }

  private class SaveableViewCapability implements SaveCookie {

    @Override
    public void save() throws IOException {
      ISaveableDocCapability saveable = dataProvider.getLookup().lookup(ISaveableDocCapability.class);
      try {
        doc.setAbbrev(docAbbrev.getText());
        doc.setWorkName(docWorkName.getText());
        doc.setTitle(docTitle.getText());
        doc.setAuthor(docAuthor.getText());
        doc.setDescription(docDescrip.getText());
        
        saveable.save(doc);
      } catch (Exception ex) {
        logger.log(Level.WARNING, null, ex); //TODO provide a message from Bundle
      }
      IReloadableDocCapability r = dataProvider.getLookup().lookup(IReloadableDocCapability.class);
      try {
        r.reload();
      } catch (Exception e) {
        logger.log(Level.WARNING, null, e); //TODO provide a message from Bundle
      }

      CentralLookup cl = CentralLookup.getDefault();
      Collection<? extends IRefreshableDocViewCapability> nodes = cl.lookupAll(IRefreshableDocViewCapability.class);
      for (IRefreshableDocViewCapability rvc : nodes) {
        try {
          rvc.refreshAfterEdit(doc);
        } catch (Exception ex) {
          logger.log(Level.WARNING, null, ex); //TODO provide a message from Bundle
        }
      }

      fire(false);
    }
  }

  private class ShowParentCookie implements ILinkedWindow {

    @Override
    public void showParent() {
      DocEditTopComponent.this.tcOpenedFrom.requestActive();
    }
  }
}
